#include "ScriptPCH.h"
#include "EscortAI.h"

enum CaptainTyralius
{
    NPC_CAPTAIN_TYRALIUS    = 20787,
    SAY_FREE                = 0,
};

class go_captain_tyralius_prison : public GameObjectScript
{
    public:
        go_captain_tyralius_prison() : GameObjectScript("go_captain_tyralius_prison") { }

        bool OnGossipHello(Player* pPlayer, GameObject* pGO)
        {
            Creature* pTyralius = pGO->FindNearestCreature(NPC_CAPTAIN_TYRALIUS, 1.0f);
            if(pTyralius)
            {
                pGO->UseDoorOrButton();

                if(pPlayer)
                    pPlayer->KilledMonsterCredit(NPC_CAPTAIN_TYRALIUS);

                pTyralius->AI()->Talk(SAY_FREE);
                pTyralius->ForcedDespawn(8000);
            }
            return true;
        }
};

enum eManaforgeConsoleData
{
    EMOTE_START                 = -1000211,
    EMOTE_60                    = -1000212,
    EMOTE_30                    = -1000213,
    EMOTE_10                    = -1000214,
    EMOTE_COMPLETE              = -1000215,
    EMOTE_ABORT                 = -1000216,

    ENTRY_BNAAR_C_CONSOLE       = 20209,
    ENTRY_CORUU_C_CONSOLE       = 20417,
    ENTRY_DURO_C_CONSOLE        = 20418,
    ENTRY_ARA_C_CONSOLE         = 20440,

    ENTRY_SUNFURY_TECH          = 20218,
    ENTRY_SUNFURY_PROT          = 20436,

    ENTRY_ARA_TECH              = 20438,
    ENTRY_ARA_ENGI              = 20439,
    ENTRY_ARA_GORKLONN          = 20460,

    SPELL_DISABLE_VISUAL        = 35031,
    SPELL_INTERRUPT_1           = 35016,                       //ACID mobs should cast this
    SPELL_INTERRUPT_2           = 35176,                       //ACID mobs should cast this (Manaforge Ara-version)
};

class npc_manaforge_control_console : public CreatureScript
{
public:
    npc_manaforge_control_console() : CreatureScript("npc_manaforge_control_console") { }

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new npc_manaforge_control_consoleAI(pCreature);
    }

    struct npc_manaforge_control_consoleAI : public ScriptedAI
    {
        npc_manaforge_control_consoleAI(Creature* pCreature) : ScriptedAI(pCreature) { }

        uint32 Event_Timer;
        uint32 Wave_Timer;
        uint32 Phase;
        bool Wave;
        ObjectGuid someplayer;
        ObjectGuid goConsole;
        Creature* add;

        void Reset()
        {
            Event_Timer = 3000;
            Wave_Timer = 0;
            Phase = 1;
            Wave = false;
            someplayer.Clear();
            goConsole.Clear();
            add = NULL;
        }

        void EnterCombat(Unit* /*pWho*/) { }

        void JustDied(Unit* /*pKiller*/)
        {
            DoScriptText(EMOTE_ABORT, me);

            if(someplayer)
            {
                Unit* p = ObjectAccessor::GetUnit((*me), someplayer);
                if(p && p->GetTypeId() == TYPEID_PLAYER)
                    if(Player* plr = p->ToPlayer())
                {
                    switch(me->GetEntry())
                    {
                        case ENTRY_BNAAR_C_CONSOLE:
                            plr->FailQuest(10299);
                            plr->FailQuest(10329);
                            break;
                        case ENTRY_CORUU_C_CONSOLE:
                            plr->FailQuest(10321);
                            plr->FailQuest(10330);
                            break;
                        case ENTRY_DURO_C_CONSOLE:
                            plr->FailQuest(10322);
                            plr->FailQuest(10338);
                            break;
                        case ENTRY_ARA_C_CONSOLE:
                            plr->FailQuest(10323);
                            plr->FailQuest(10365);
                            break;
                    }
                }
            }

            if(goConsole)
            {
                if(GameObject* pGo = GameObject::GetGameObject((*me), goConsole))
                    pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
            }
        }

        void DoWaveSpawnForCreature(Creature* creature)
        {
            switch(creature->GetEntry())
            {
                case ENTRY_BNAAR_C_CONSOLE:
                    if(rand()%2)
                    {
                        add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2933.68f, 4162.55f, 164.00f, 1.60f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 2927.36f, 4212.97f, 164.00f);
                    }
                    else
                    {
                        add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2927.36f, 4212.97f, 164.00f, 4.94f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 2933.68f, 4162.55f, 164.00f);
                    }
                    Wave_Timer = 30000;
                    break;
                case ENTRY_CORUU_C_CONSOLE:
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2445.21f, 2765.26f, 134.49f, 3.93f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2424.21f, 2740.15f, 133.81f);
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2429.86f, 2731.85f, 134.53f, 1.31f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2435.37f, 2766.04f, 133.81f);
                    Wave_Timer = 20000;
                    break;
                case ENTRY_DURO_C_CONSOLE:
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2986.80f, 2205.36f, 165.37f, 3.74f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2985.15f, 2197.32f, 164.79f);
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2952.91f, 2191.20f, 165.32f, 0.22f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2060.01f, 2185.27f, 164.67f);
                    Wave_Timer = 15000;
                    break;
                case ENTRY_ARA_C_CONSOLE:
                    if(rand()%2)
                    {
                        add = me->SummonCreature(ENTRY_ARA_TECH, 4035.11f, 4038.97f, 194.27f, 2.57f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 4003.42f, 4040.19f, 193.49f);
                        add = me->SummonCreature(ENTRY_ARA_TECH, 4033.66f, 4036.79f, 194.28f, 2.57f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 4003.42f, 4040.19f, 193.49f);
                        add = me->SummonCreature(ENTRY_ARA_TECH, 4037.13f, 4037.30f, 194.23f, 2.57f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 4003.42f, 4040.19f, 193.49f);
                    }
                    else
                    {
                        add = me->SummonCreature(ENTRY_ARA_TECH, 3099.59f, 4049.30f, 194.22f, 0.05f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 4028.01f, 4035.17f, 193.59f);
                        add = me->SummonCreature(ENTRY_ARA_TECH, 3999.72f, 4046.75f, 194.22f, 0.05f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 4028.01f, 4035.17f, 193.59f);
                        add = me->SummonCreature(ENTRY_ARA_TECH, 3996.81f, 4048.26f, 194.22f, 0.05f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        if(add) add->GetMotionMaster()->MovePoint(0, 4028.01f, 4035.17f, 193.59f);
                    }
                    Wave_Timer = 15000;
                    break;
            }
        }
        void DoFinalSpawnForCreature(Creature* creature)
        {
            switch(creature->GetEntry())
            {
                case ENTRY_BNAAR_C_CONSOLE:
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2946.52f, 4201.42f, 163.47f, 3.54f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2927.49f, 4192.81f, 163.00f);
                    break;
                case ENTRY_CORUU_C_CONSOLE:
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2453.88f, 2737.85f, 133.27f, 2.59f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2433.96f, 2751.53f, 133.85f);
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2441.62f, 2735.32f, 134.49f, 1.97f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2433.96f, 2751.53f, 133.85f);
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2450.73f, 2754.50f, 134.49f, 3.29f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2433.96f, 2751.53f, 133.85f);
                    break;
                case ENTRY_DURO_C_CONSOLE:
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2956.18f, 2202.85f, 165.32f, 5.45f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2972.27f, 2193.22f, 164.48f);
                    add = me->SummonCreature(ENTRY_SUNFURY_TECH, 2975.30f, 2211.50f, 165.32f, 4.55f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2972.27f, 2193.22f, 164.48f);
                    add = me->SummonCreature(ENTRY_SUNFURY_PROT, 2965.02f, 2217.45f, 164.16f, 4.96f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 2972.27f, 2193.22f, 164.48f);
                    break;
                case ENTRY_ARA_C_CONSOLE:
                    add = me->SummonCreature(ENTRY_ARA_ENGI, 3994.51f, 4020.46f, 192.18f, 0.91f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 4008.35f, 4035.04f, 192.70f);
                    add = me->SummonCreature(ENTRY_ARA_GORKLONN, 4021.56f, 4059.35f, 193.59f, 4.44f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                    if(add) add->GetMotionMaster()->MovePoint(0, 4016.62f, 4039.89f, 193.46f);
                    break;
            }
        }

        void UpdateAI(const uint32 diff)
        {
            if(Event_Timer <= diff)
            {
                switch(Phase)
                {
                    case 1:
                        if(someplayer)
                        {
                            Unit* u = ObjectAccessor::GetUnit((*me), someplayer);
                            if(u && u->GetTypeId() == TYPEID_PLAYER) DoScriptText(EMOTE_START, me, u);
                        }
                        Event_Timer = 60000;
                        Wave = true;
                        ++Phase;
                        break;
                    case 2:
                        DoScriptText(EMOTE_60, me);
                        Event_Timer = 30000;
                        ++Phase;
                        break;
                    case 3:
                        DoScriptText(EMOTE_30, me);
                        Event_Timer = 20000;
                        DoFinalSpawnForCreature(me);
                        ++Phase;
                        break;
                    case 4:
                        DoScriptText(EMOTE_10, me);
                        Event_Timer = 10000;
                        Wave = false;
                        ++Phase;
                        break;
                    case 5:
                        DoScriptText(EMOTE_COMPLETE, me);
                        if(someplayer)
                        {
                            Unit* u = ObjectAccessor::GetUnit((*me), someplayer);
                            if(u && u->GetTypeId() == TYPEID_PLAYER)
                                if(Player* plr = u->ToPlayer())
                                    plr->KilledMonsterCredit(me->GetEntry(), me->GetGUID());
                            DoCast(me, SPELL_DISABLE_VISUAL);
                        }
                        if(goConsole)
                        {
                            if(GameObject* pGo = GameObject::GetGameObject((*me), goConsole))
                                pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
                        }
                        ++Phase;
                        break;
                }
            } else Event_Timer -= diff;

            if(Wave)
            {
                if(Wave_Timer <= diff)
                {
                    DoWaveSpawnForCreature(me);
                } else Wave_Timer -= diff;
            }
        }
    };
};

//TODO: clean up this workaround when Trinity adds support to do it properly (with gossip selections instead of instant summon)
class go_manaforge_control_console : public GameObjectScript
{
public:
    go_manaforge_control_console() : GameObjectScript("go_manaforge_control_console") { }

    bool OnGossipHello(Player* player, GameObject* pGo)
    {
        if(pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
        {
            player->PrepareQuestMenu(pGo->GetGUID());
            player->SendPreparedQuest(pGo->GetGUID());
        }

        Creature* manaforge = NULL;

        switch(pGo->GetAreaId())
        {
            case 3726:                                          //b'naar
                if((player->GetQuestStatus(10299) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10329) == QUEST_STATUS_INCOMPLETE) &&
                    player->HasItemCount(29366, 1))
                    manaforge = player->SummonCreature(ENTRY_BNAAR_C_CONSOLE, 2918.95f, 4189.98f, 161.88f, 0.34f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000);
                break;
            case 3730:                                          //coruu
                if((player->GetQuestStatus(10321) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10330) == QUEST_STATUS_INCOMPLETE) &&
                    player->HasItemCount(29396, 1))
                    manaforge = player->SummonCreature(ENTRY_CORUU_C_CONSOLE, 2426.77f, 2750.38f, 133.24f, 2.14f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000);
                break;
            case 3734:                                          //duro
                if((player->GetQuestStatus(10322) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10338) == QUEST_STATUS_INCOMPLETE) &&
                    player->HasItemCount(29397, 1))
                    manaforge = player->SummonCreature(ENTRY_DURO_C_CONSOLE, 2976.48f, 2183.29f, 163.20f, 1.85f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000);
                break;
            case 3722:                                          //ara
                if((player->GetQuestStatus(10323) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(10365) == QUEST_STATUS_INCOMPLETE) &&
                    player->HasItemCount(29411, 1))
                    manaforge = player->SummonCreature(ENTRY_ARA_C_CONSOLE, 4013.71f, 4028.76f, 192.10f, 1.25f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 125000);
                break;
        }

        if(manaforge)
        {
            CAST_AI(npc_manaforge_control_console::npc_manaforge_control_consoleAI, manaforge->AI())->someplayer.Set(player->GetGUID());
            CAST_AI(npc_manaforge_control_console::npc_manaforge_control_consoleAI, manaforge->AI())->goConsole.Set(pGo->GetGUID());
            pGo->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
        }
        return true;
    }
};

// The Speech of Dawnforge, Ardonis & Pathaleon
enum eCommanderDawnforgeData
{
    SAY_COMMANDER_DAWNFORGE_1       = -1000128,
    SAY_ARCANIST_ARDONIS_1          = -1000129,
    SAY_COMMANDER_DAWNFORGE_2       = -1000130,
    SAY_PATHALEON_CULATOR_IMAGE_1   = -1000131,
    SAY_COMMANDER_DAWNFORGE_3       = -1000132,
    SAY_PATHALEON_CULATOR_IMAGE_2   = -1000133,
    SAY_PATHALEON_CULATOR_IMAGE_2_1 = -1000134,
    SAY_PATHALEON_CULATOR_IMAGE_2_2 = -1000135,
    SAY_COMMANDER_DAWNFORGE_4       = -1000136,
    SAY_ARCANIST_ARDONIS_2          = -1000136,
    SAY_COMMANDER_DAWNFORGE_5       = -1000137,

    QUEST_INFO_GATHERING            = 10198,
    SPELL_SUNFURY_DISGUISE          = 34603,
};

// Entries of Arcanist Ardonis, Commander Dawnforge, Pathaleon the Curators Image
const uint32 CreatureEntry[3] =
{
    19830,                                                // Ardonis
    19831,                                                // Dawnforge
    21504                                                 // Pathaleon
};

class npc_commander_dawnforge : public CreatureScript
{
public:
    npc_commander_dawnforge() : CreatureScript("npc_commander_dawnforge") { }

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new npc_commander_dawnforgeAI(pCreature);
    }

    struct npc_commander_dawnforgeAI : public ScriptedAI
    {
        npc_commander_dawnforgeAI(Creature* pCreature) : ScriptedAI(pCreature) { Reset (); }

        ObjectGuid PlayerGUID;
        ObjectGuid ardonisGUID;
        ObjectGuid pathaleonGUID;

        uint32 Phase;
        uint32 PhaseSubphase;
        uint32 Phase_Timer;
        bool isEvent;

        float angle_dawnforge;
        float angle_ardonis;

        void Reset()
        {
            PlayerGUID.Clear();
            ardonisGUID.Clear();
            pathaleonGUID.Clear();

            Phase = 1;
            PhaseSubphase = 0;
            Phase_Timer = 4000;
            isEvent = false;
        }

        void EnterCombat(Unit* /*pWho*/) { }

        void JustSummoned(Creature* summoned)
        {
            pathaleonGUID = summoned->GetGUID();
        }

        // Emote Ardonis and Pathaleon
        void Turn_to_Pathaleons_Image()
        {
            Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID);
            Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID);
            Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);

            if(!ardonis || !pathaleon || !player)
                return;

            //Calculate the angle to Pathaleon
            angle_dawnforge = me->GetAngle(pathaleon->GetPositionX(), pathaleon->GetPositionY());
            angle_ardonis = ardonis->GetAngle(pathaleon->GetPositionX(), pathaleon->GetPositionY());

            //Turn Dawnforge and update
            me->SetOrientation(angle_dawnforge);
            me->SendUpdateToPlayer(player);
            //Turn Ardonis and update
            ardonis->SetOrientation(angle_ardonis);
            ardonis->SendUpdateToPlayer(player);

            //Set them to kneel
            me->SetStandState(UNIT_STAND_STATE_KNEEL);
            ardonis->SetStandState(UNIT_STAND_STATE_KNEEL);
        }

        //Set them back to each other
        void Turn_to_eachother()
        {
            if(Unit* ardonis = ObjectAccessor::GetUnit(*me, ardonisGUID))
            {
                Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);

                if(!player)
                    return;

                angle_dawnforge = me->GetAngle(ardonis->GetPositionX(), ardonis->GetPositionY());
                angle_ardonis = ardonis->GetAngle(me->GetPositionX(), me->GetPositionY());

                //Turn Dawnforge and update
                me->SetOrientation(angle_dawnforge);
                me->SendUpdateToPlayer(player);
                //Turn Ardonis and update
                ardonis->SetOrientation(angle_ardonis);
                ardonis->SendUpdateToPlayer(player);

                //Set state
                me->SetStandState(UNIT_STAND_STATE_STAND);
                ardonis->SetStandState(UNIT_STAND_STATE_STAND);
            }
        }

        bool CanStartEvent(Player* player)
        {
            if(!isEvent)
            {
                Creature* ardonis = me->FindNearestCreature(CreatureEntry[0], 10.0f);
                if(!ardonis)
                    return false;

                ardonisGUID.Set(ardonis->GetGUID());
                PlayerGUID.Set(player->GetGUID());

                isEvent = true;

                Turn_to_eachother();
                return true;
            }

            // sLog->outDebug(LOG_FILTER_TSCR, "TSCR: npc_commander_dawnforge event already in progress, need to wait.");
            return false;
        }

        void UpdateAI(const uint32 diff)
        {
            //Is event even running?
            if(!isEvent)
                return;

            //Phase timing
            if(Phase_Timer >= diff)
            {
                Phase_Timer -= diff;
                return;
            }

            Unit* ardonis = ObjectAccessor::GetUnit(*me, ardonisGUID);
            Unit* pathaleon = ObjectAccessor::GetUnit(*me, pathaleonGUID);
            Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID);

            if(!ardonis || !player)
            {
                Reset();
                return;
            }

            if(Phase > 4 && !pathaleon)
            {
                Reset();
                return;
            }

            //Phase 1 Dawnforge say
            switch(Phase)
            {
            case 1:
                DoScriptText(SAY_COMMANDER_DAWNFORGE_1, me);
                ++Phase;
                Phase_Timer = 16000;
                break;
                //Phase 2 Ardonis say
            case 2:
                DoScriptText(SAY_ARCANIST_ARDONIS_1, ardonis);
                ++Phase;
                Phase_Timer = 16000;
                break;
                //Phase 3 Dawnforge say
            case 3:
                DoScriptText(SAY_COMMANDER_DAWNFORGE_2, me);
                ++Phase;
                Phase_Timer = 16000;
                break;
                //Phase 4 Pathaleon spawns up to phase 9
            case 4:
                //spawn pathaleon's image
                me->SummonCreature(CreatureEntry[2], 2325.851563f, 2799.534668f, 133.084229f, 6.038996f, TEMPSUMMON_TIMED_DESPAWN, 90000);
                ++Phase;
                Phase_Timer = 500;
                break;
                //Phase 5 Pathaleon say
            case 5:
                DoScriptText(SAY_PATHALEON_CULATOR_IMAGE_1, pathaleon);
                ++Phase;
                Phase_Timer = 6000;
                break;
                //Phase 6
            case 6:
                switch(PhaseSubphase)
                {
                    case 0: //Subphase 1: Turn Dawnforge and Ardonis
                        Turn_to_Pathaleons_Image();
                        ++PhaseSubphase;
                        Phase_Timer = 8000;
                        break;
                    case 1: //Subphase 2 Dawnforge say
                        DoScriptText(SAY_COMMANDER_DAWNFORGE_3, me);
                        PhaseSubphase = 0;
                        ++Phase;
                        Phase_Timer = 8000;
                        break;
                }
                break;
                //Phase 7 Pathaleons say 3 Sentence, every sentence need a subphase
            case 7:
                switch(PhaseSubphase)
                {
                    case 0: //Subphase 1
                        DoScriptText(SAY_PATHALEON_CULATOR_IMAGE_2, pathaleon);
                        ++PhaseSubphase;
                        Phase_Timer = 12000;
                        break;
                    case 1: //Subphase 2
                        DoScriptText(SAY_PATHALEON_CULATOR_IMAGE_2_1, pathaleon);
                        ++PhaseSubphase;
                        Phase_Timer = 16000;
                        break;
                    case 2: //Subphase 3
                        DoScriptText(SAY_PATHALEON_CULATOR_IMAGE_2_2, pathaleon);
                        PhaseSubphase = 0;
                        ++Phase;
                        Phase_Timer = 10000;
                        break;
                }
                break;
                //Phase 8 Dawnforge & Ardonis say
            case 8:
                DoScriptText(SAY_COMMANDER_DAWNFORGE_4, me);
                DoScriptText(SAY_ARCANIST_ARDONIS_2, ardonis);
                ++Phase;
                Phase_Timer = 4000;
                break;
                //Phase 9 Pathaleons Despawn, Reset Dawnforge & Ardonis angle
            case 9:
                Turn_to_eachother();
                //hide pathaleon, unit will despawn shortly
                pathaleon->SetVisible(false);
                PhaseSubphase = 0;
                ++Phase;
                Phase_Timer = 3000;
                break;
                //Phase 10 Dawnforge say
            case 10:
                DoScriptText(SAY_COMMANDER_DAWNFORGE_5, me);
                player->AreaExploredOrEventHappens(QUEST_INFO_GATHERING);
                Reset();
                break;
            }
         }
    };
};

class at_commander_dawnforge : public AreaTriggerScript
{
public:
    at_commander_dawnforge() : AreaTriggerScript("at_commander_dawnforge") { }

    bool OnTrigger(Player* player, const AreaTriggerEntry * /*at*/)
    {
        //if player lost aura or not have at all, we should not try start event.
        if(!player->HasAura(SPELL_SUNFURY_DISGUISE))
            return false;

        if(player->IsAlive() && player->GetQuestStatus(QUEST_INFO_GATHERING) == QUEST_STATUS_INCOMPLETE)
        {
            Creature* Dawnforge = player->FindNearestCreature(CreatureEntry[1], 30.0f);

            if(!Dawnforge)
                return false;

            if(CAST_AI(npc_commander_dawnforge::npc_commander_dawnforgeAI, Dawnforge->AI())->CanStartEvent(player))
                return true;
        }
        return false;
    }
};

enum eProfessorDabiriData
{
    SPELL_PHASE_DISTRUPTOR  = 35780,

    WHISPER_DABIRI          = -1000522,

    QUEST_DIMENSIUS         = 10439,
    QUEST_ON_NETHERY_WINGS  = 10438,
};

#define GOSSIP_ITEM "I need a new phase distruptor, Professor"

class npc_professor_dabiri : public CreatureScript
{
public:
    npc_professor_dabiri() : CreatureScript("npc_professor_dabiri") { }

    bool OnQuestAccept(Player* player, Creature* creature, Quest const *quest)
    {
        if(quest->GetQuestId() == QUEST_DIMENSIUS)
            DoScriptText(WHISPER_DABIRI, creature, player);

        return true;
    }

    bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction)
    {
        ClearGossipMenuFor(player);
        if(uiAction == GOSSIP_ACTION_INFO_DEF+1)
        {
            creature->CastSpell(player, SPELL_PHASE_DISTRUPTOR, false);
            CloseGossipMenuFor(player);
        }

        return true;
    }

    bool OnGossipHello(Player* player, Creature* creature)
    {
        if(creature->IsQuestGiver())
            player->PrepareQuestMenu(creature->GetGUID());

        if(player->GetQuestStatus(QUEST_ON_NETHERY_WINGS) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(29778, 1))
            AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);

        SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());

        return true;
    }
};

enum ePhaseHunterData
{
    QUEST_RECHARGING_THE_BATTERIES  = 10190,

    NPC_PHASE_HUNTER_ENTRY          = 18879,
    NPC_DRAINED_PHASE_HUNTER_ENTRY  = 19595,

    EMOTE_WEAK                      = -1000303,

    // Spells
    SPELL_RECHARGING_BATTERY        = 34219,
    SPELL_PHASE_SLIP                = 36574,
    SPELL_MANA_BURN                 = 13321,
    SPELL_MATERIALIZE               = 34804,
    SPELL_DE_MATERIALIZE            = 34814,
};

class mob_phase_hunter : public CreatureScript
{
public:
    mob_phase_hunter() : CreatureScript("mob_phase_hunter") { }

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new mob_phase_hunterAI(pCreature);
    }

    struct mob_phase_hunterAI : public ScriptedAI
    {
        mob_phase_hunterAI(Creature* pCreature) : ScriptedAI(pCreature) { }

        bool Weak;
        bool Materialize;
        bool Drained;
        uint8 WeakPercent;

        Player* player;
        ObjectGuid PlayerGUID;

        uint32 ManaBurnTimer;

        void Reset()
        {
            Weak = false;
            Materialize = false;
            Drained = false;
            WeakPercent = 25 + (rand() % 16); // 25-40

            PlayerGUID.Clear();

            ManaBurnTimer = 5000 + (rand() % 3 * 1000); // 5-8 sec cd

            if(me->GetEntry() == NPC_DRAINED_PHASE_HUNTER_ENTRY)
                me->UpdateEntry(NPC_PHASE_HUNTER_ENTRY);
        }

        void EnterCombat(Unit* who)
        {
            if(who->GetTypeId() == TYPEID_PLAYER)
                PlayerGUID.Set(who->GetGUID());
        }

        void SpellHit(Unit* /*pCaster*/, const SpellInfo* /*spell*/)
        {
            DoCast(me, SPELL_DE_MATERIALIZE);
        }

        void UpdateAI(const uint32 diff)
        {
            if(!Materialize)
            {
                DoCast(me, SPELL_MATERIALIZE);
                Materialize = true;
            }

            if(me->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || me->HasUnitState(UNIT_STATE_ROOT)) // if the mob is rooted/slowed by spells eg.: Entangling Roots, Frost Nova, Hamstring, Crippling Poison, etc. => remove it
                DoCast(me, SPELL_PHASE_SLIP);

            if(!UpdateVictim())
                return;

            // some code to cast spell Mana Burn on random target which has mana
            // @todo
            /*
            if(ManaBurnTimer <= diff)
            {
                std::list<HostileReference*> AggroList = me->getThreatManager().getThreatList();
                std::list<Unit*> UnitsWithMana;

                for(std::list<HostileReference*>::const_iterator itr = AggroList.begin(); itr != AggroList.end(); ++itr)
                {
                    if(Unit* pUnit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
                    {
                        if(pUnit->GetCreateMana() > 0)
                            UnitsWithMana.push_back(pUnit);
                    }
                }
                if(!UnitsWithMana.empty())
                {
                    std::list<Unit*>::const_iterator it = UnitsWithMana.begin();
                    std::advance(it, rand() % UnitsWithMana.size());
                    DoCast(*it, SPELL_MANA_BURN);
                    ManaBurnTimer = 8000 + (rand() % 10 * 1000); // 8-18 sec cd
                }
                else
                    ManaBurnTimer = 3500;
            } else ManaBurnTimer -= diff;
            */

            if(Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) // start: support for quest 10190
            {
                if(!Weak && HealthBelowPct(WeakPercent)
                    && player->GetQuestStatus(QUEST_RECHARGING_THE_BATTERIES) == QUEST_STATUS_INCOMPLETE)
                {
                    DoScriptText(EMOTE_WEAK, me);
                    Weak = true;
                }
                if(Weak && !Drained && me->HasAura(SPELL_RECHARGING_BATTERY))
                {
                    Drained = true;
                    int32 uHpPct = int32(me->GetHealthPct());

                    me->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);

                    me->SetHealth(me->CountPctFromMaxHealth(uHpPct));
                    me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth());
                    me->SetInCombatWith(player);
                }
            } // end: support for quest 10190

            DoMeleeAttackIfReady();
        }
    };
};

enum eBessyData
{
    Q_ALMABTRIEB    = 10337,
    N_THADELL       = 20464,
    SPAWN_FIRST     = 20512,
    SPAWN_SECOND    = 19881,
    SAY_THADELL_1   = -1000524,
    SAY_THADELL_2   = -1000525,
};

class npc_bessy : public CreatureScript
{
public:
    npc_bessy() : CreatureScript("npc_bessy") { }

    bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest)
    {
        if(quest->GetQuestId() == Q_ALMABTRIEB)
        {
            creature->SetFaction(113);
            creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
            CAST_AI(EscortAI, (creature->AI()))->Start(true, false, player->GetGUID());
        }
        return true;
    }

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new npc_bessyAI(pCreature);
    }

    struct npc_bessyAI : public EscortAI
    {
        npc_bessyAI(Creature* pCreature) : EscortAI(pCreature) { }

        void JustDied(Unit* /*pKiller*/)
        {
            if(Player* player = GetPlayerForEscort())
                player->FailQuest(Q_ALMABTRIEB);
        }

        void WaypointReached(uint32 i, uint32)
        {
            Player* player = GetPlayerForEscort();

            if(!player)
                return;

            switch(i)
            {
                case 3: //first spawn
                    me->SummonCreature(SPAWN_FIRST, 2449.67f, 2183.11f, 96.85f, 6.20f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
                    me->SummonCreature(SPAWN_FIRST, 2449.53f, 2184.43f, 96.36f, 6.27f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
                    me->SummonCreature(SPAWN_FIRST, 2449.85f, 2186.34f, 97.57f, 6.08f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
                    break;
                case 7:
                    me->SummonCreature(SPAWN_SECOND, 2309.64f, 2186.24f, 92.25f, 6.06f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
                    me->SummonCreature(SPAWN_SECOND, 2309.25f, 2183.46f, 91.75f, 6.22f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
                    break;
                case 12:
                    if(player)
                        player->GroupEventHappens(Q_ALMABTRIEB, me);
                    if(me->FindNearestCreature(N_THADELL, 30))
                        DoScriptText(SAY_THADELL_1, me); break;
                case 13:
                    if(me->FindNearestCreature(N_THADELL, 30))
                        DoScriptText(SAY_THADELL_2, me, player); break;
            }
        }

        void JustSummoned(Creature* summoned)
        {
            summoned->AI()->AttackStart(me);
        }

        void Reset()
        {
            me->RestoreFaction();
        }

    };
};

enum eMillionEscort
{
    QUEST_MARK_V_IS_ALIVE = 10191,
    GO_DRAENEI_MACHINE = 183771
};

class npc_maxx_a_million_escort : public CreatureScript
{
public:
    npc_maxx_a_million_escort() : CreatureScript("npc_maxx_a_million_escort") { }

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new npc_maxx_a_million_escortAI(pCreature);
    }

    struct npc_maxx_a_million_escortAI : public EscortAI
    {
        npc_maxx_a_million_escortAI(Creature* pCreature) : EscortAI(pCreature) { }

        bool bTake;
        uint32 uiTakeTimer;

        void Reset()
        {
            bTake=false;
            uiTakeTimer=3000;
        }

        void WaypointReached(uint32 i, uint32)
        {
            Player* player = GetPlayerForEscort();
            if(!player)
                return;

            switch(i)
            {
                case 7:
                case 17:
                case 29:
                    //Find Object and "work"
                    if(GetClosestGameObjectWithEntry(me, GO_DRAENEI_MACHINE, INTERACTION_DISTANCE))
                    {
                        // take the GO -> animation
                        // @todo
                        // me->HandleEmoteCommand(EMOTE_STATE_LOOT);
                        SetEscortPaused(true);
                        bTake=true;
                    }
                    break;
                case 36: //return and quest_complete
                    if(player)
                        player->CompleteQuest(QUEST_MARK_V_IS_ALIVE);
                    break;
            }
        }

        void JustDied(Unit* /*pKiller*/)
        {
            Player* player = GetPlayerForEscort();
            if(player)
                player->FailQuest(QUEST_MARK_V_IS_ALIVE);
        }

        void UpdateAI(const uint32 diff)
        {
            EscortAI::UpdateAI(diff);

            if(bTake)
            {
                if(uiTakeTimer < diff)
                {
                    me->HandleEmoteCommand(EMOTE_STATE_NONE);
                    if(GameObject* pGO = GetClosestGameObjectWithEntry(me, GO_DRAENEI_MACHINE, INTERACTION_DISTANCE))
                    {
                        SetEscortPaused(false);
                        bTake=false;
                        uiTakeTimer = 3000;
                        pGO->Delete();
                    }
                }
                else
                    uiTakeTimer -= diff;
            }
            DoMeleeAttackIfReady();
        }
    };

    bool OnQuestAccept(Player* player, Creature* creature, const Quest* pQuest)
    {
        if(pQuest->GetQuestId() == QUEST_MARK_V_IS_ALIVE)
        {
            if(npc_maxx_a_million_escortAI* pEscortAI = CAST_AI(npc_maxx_a_million_escort::npc_maxx_a_million_escortAI, creature->AI()))
            {
                creature->SetFaction(113);
                pEscortAI->Start(false, false, player->GetGUID());
            }
        }
        return true;
    }
};

class npc_windtradermarid : public CreatureScript
{
public:
    npc_windtradermarid() : CreatureScript("npc_windtradermarid") { }

    bool OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction)
    {
        ClearGossipMenuFor(pPlayer);
        if(uiAction == GOSSIP_ACTION_INFO_DEF+1)
        {
            if(Creature* pSummon = pCreature->SummonCreature(20071, 4280.453f, 2229.066f, 124.217f, 6.172f, TEMPSUMMON_TIMED_DESPAWN, 180000))
                pSummon->SetFaction(14);

            CloseGossipMenuFor(pPlayer);
        }

        return true;
    }

    bool OnGossipHello(Player* pPlayer, Creature* pCreature)
    {
        if(pCreature->IsQuestGiver())
            pPlayer->PrepareQuestMenu(pCreature->GetGUID());

        if(pPlayer->GetQuestStatus(10273) == QUEST_STATUS_INCOMPLETE)
            AddGossipItemFor(pPlayer, GOSSIP_ICON_CHAT, "Fight!", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);

        SendGossipMenuFor(pPlayer, pPlayer->GetGossipTextId(pCreature), pCreature->GetGUID());

        return true;
    }
};

class npc_protectorate_demolitionist : public CreatureScript
{
public:
    npc_protectorate_demolitionist() : CreatureScript("npc_protectorate_demolitionist") { }

    struct npc_protectorate_demolitionistAI : public ScriptedAI
    {
        npc_protectorate_demolitionistAI(Creature* pCreature): ScriptedAI(pCreature) { }

        uint32 EventCheck_Timer;

        void Reset()
        {
            EventCheck_Timer = 2500;

            me->GetMotionMaster()->Clear();
            me->GetMotionMaster()->MoveIdle();
            if(Unit* pOwner = me->GetCharmerOrOwner())
                me->GetMotionMaster()->MoveFollow(pOwner, 1.0f, pOwner->GetOrientation());
        }

        void MoveInLineOfSight(Unit* pWho)
        {
            if(!me->GetCharmerOrOwner() && pWho && pWho->GetTypeId() == TYPEID_PLAYER && pWho->HasAura(35679)) {
                me->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, pWho->GetGUID());
                // @todo me->SetCharmerGUID(pWho->GetGUID());    //WTF?? SetCharmedBy() ?
                me->GetMotionMaster()->MoveFollow(pWho, 1.0f, pWho->GetOrientation());
            }
        }

        void UpdateAI(const uint32 diff)
        {
            if(UpdateVictim())
                DoMeleeAttackIfReady();

            if(EventCheck_Timer <= diff)
            {
                if(!me->GetCharmerOrOwner())
                {
                    // @todo me->SetCharmerGUID(0);  //hotfix. TODO: rewrite this shit completely with EscortAI!
                    me->DespawnOrUnsummon();
                }

                if(me->FindNearestCreature(20755, 20.0f))
                {
                    me->GetCharmerOrOwner()->ToPlayer()->CompleteQuest(10406);
                    me->RemoveCharmedBy(me->GetCharmerOrOwner());
                    me->DespawnOrUnsummon();
                }

                EventCheck_Timer = 1000;
                return;
            } else {
                EventCheck_Timer -= diff;
                return;
            }
        }
    };

    CreatureAI* GetAI(Creature* pCreature) const
    {
        return new npc_protectorate_demolitionistAI(pCreature);
    }
};

void AddSC_netherstorm()
{
    new go_captain_tyralius_prison;
    new go_manaforge_control_console;
    new npc_manaforge_control_console;
    new npc_commander_dawnforge;
    new at_commander_dawnforge;
    new npc_professor_dabiri;
    new mob_phase_hunter;
    new npc_bessy;
    new npc_maxx_a_million_escort;
    new npc_windtradermarid;
    new npc_protectorate_demolitionist;
}
